#include "TcpServer.h"

#include "tcp/Channel.h"
#include "tcp/SocketUtils.h"
#include "../base/log/Logging.h"


TcpServer::TcpServer(EventLoop *loop,
                     const InetAddress &listenAddr,
                     std::string name,
                     Option option) :
        loop_(loop),
        name_(std::move(name)),
        acceptor_(new Acceptor(loop, listenAddr, option == Option::kReusePort)),
        threadPool_(new EventLoopThreadPool(loop, name_)),
        started_(false),
        nextConnId_(1) {
    acceptor_->setNewConnectionCallback(
            std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
    // 将setNewConnectionCallback封装到Acceptor中
}

TcpServer::~TcpServer() {
    loop_->assertInLoopThread();
    //   LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing";

    for (auto &item : connections_) {
        TcpConnectionPtr conn(item.second);
        item.second.reset();
        conn->getLoop()->runInLoop(
                std::bind(&TcpConnection::connectDestroyed, conn));
    }
}

void TcpServer::setThreadNum(int numThreads) {
    assert(0 <= numThreads);
    threadPool_->setThreadNum(numThreads);
}

void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr) {
    loop_->assertInLoopThread();
    EventLoop *ioLoop_ = threadPool_->getNextLoop();
    // 获取io事件循环, 用于处理新连接
    char buf[64];
    snprintf(buf, sizeof buf, "#%d", nextConnId_);
    ++nextConnId_;
    std::string connName = name_ + buf;

    LOG_DEBUG << "TcpServer::newConnection [" << name_
              << "] - new connection [" << connName
              << "] from " << peerAddr.toIpPort();

    InetAddress localAddr(Socket::getLocalAddr(sockfd));
    // 获取本地sock对应的地址信息, 然后存放到conn指针总中
    TcpConnectionPtr conn(new TcpConnection(ioLoop_, connName, sockfd, localAddr, peerAddr));
    // TcpConnectionPtr conn(new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
    // 这里要对比开来, 当使用了EventLoopThreadLoop的情况下这里传入的是专门负责IO的线程
    connections_[connName] = conn;
    // 将分配的新连接管理类保存卡里
    conn->setConnectionCallback(connectionCallback_);
    conn->setMessageCallback(messageCallback_);
    conn->setWriteCompleteCallback(writeCompleteCallback_);
    conn->setCloseCallback(bind(&TcpServer::removeConnection,
                                this,
                                std::placeholders::_1));
    ioLoop_->runInLoop(std::bind(&TcpConnection::connectionEstablished, conn));
}

void TcpServer::removeConnection(const TcpConnectionPtr &conn) {
    // ssize_t n = connections_.erase(conn->getName());
    // 移除conn, 同时调用这个conn对应的移除函数
    // 负责移除这个连接对应的回调函数, 移除了这些回调函数之后没有Socket没有指向会被智能指针自动析构
    // conn->connectDestroyed();
    // 因为使用了EventLoopThreadLoop, 所以将remove的操作拆分开
    LOG_TRACE << "TcpServer::removeConnection [" << conn->getName() << "] - remove connection, connection IPPort : "
              << conn->peerAddress().toIpPort();
    loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn) {
    loop_->assertInLoopThread();
    size_t n = connections_.erase(conn->getName());
    assert(n == 1);
    (void) n;
    EventLoop *ioLoop = conn->getLoop();
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
    // 在线程中调用TcpConnection的连接销毁
}

void TcpServer::start() {
    if (!started_) {
        started_ = true;
        threadPool_->start();
        assert(!acceptor_->listening());

        LOG_TRACE << "TcpServer Start";

        loop_->runInLoop(std::bind(&Acceptor::listen, get_pointer(acceptor_)));
        // 调用 listen, listen会顺便将TcpServer的文件描述符注册到EventLoop的监听事件循环中
    }
}

